<?php

namespace app\server\notice\controller;

use app\common\model\Auth;
use app\common\model\Config;
use app\common\model\Db;
use app\server\notice\model\EmsSimple;
use app\server\notice\model\Push;
use app\server\notice\model\SmsSimple;
use variant\library\vari\Log;

class Http
{

    private $_worker;

    /**
     * 短信host
     *
     * @var
     */
    private $_smsHost;

    /**
     * 短信端口
     *
     * @var
     */
    private $_smsPort;

    /**
     * 邮件host
     *
     * @var
     */
    private $_emsHost;

    /**
     * 邮件端口
     *
     * @var
     */
    private $_emsPort;

    /**
     * 短信映射策略
     *
     * @var array
     */
    private $_smsMapStrategy = [
        'sms_1' => 'template_code_login',
        'sms_2' => 'template_code_register',
        'sms_3' => 'template_code_pwd',
        'sms_4' => 'template_new_user',
        'sms_5' => 'template_code_common',
        'sms_6' => 'template_code_re_pwd',
        'sms_7' => 'template_code_re_mobile',
    ];

    /**
     * 邮件映射策略
     *
     * @var array
     */
    private $_emsMapStrategy = [
        'ems_1' => 'login',
        'ems_2' => 'register',
        'ems_3' => 'pwd'
    ];

    /**
     * Http constructor.
     */
    public function __construct()
    {

        $this->_emsHost = Config::get('ems_server.host', 'ems');
        $this->_emsPort = Config::get('ems_server.port', 'ems');
        $this->_smsHost = Config::get('sms_server.host', 'sms');
        $this->_smsPort = Config::get('sms_server.port', 'sms');
        /**
         * 实例邮件服务
         */
        $this->_worker = new \Swoole\Http\Server($this->_emsHost, $this->_emsPort);
        /**
         * 设置
         */
        $this->_worker->set([
            'worker_num' => 2,
            'task_worker_num' => 4,
            'daemonize' => 1
        ]);
        $this->_worker->on('Request', [$this, 'onRequest']);
        $this->_worker->on('Task', [$this, 'onTask']);
        $this->_worker->on('Finish', [$this, 'onFinish']);

        /**
         * 添加端口 短信服务
         */
        $this->_worker->listen($this->_smsHost, $this->_smsPort, SWOOLE_SOCK_TCP);
        $this->_worker->start();
    }

    /**
     * 请求回调
     *
     * @param $request
     * @param $response
     * @return mixed
     */
    public function onRequest($request, $response)
    {
        if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') {
            $response->status(404);
            return $response->end();
        }

        if ($request->server['path_info'] == '/check' || $request->server['request_uri'] == '/check') {
            $response->status(200);
            return $response->end('ok');
        }

        $post = $request->post;
        $post['port'] = $request->server['server_port'];
        $token = $request->header['authorization'] ?? null;
        $post['token'] = $token;
        Log::instance()->notice(var_export($request, true));
        /**
         * 验证请求者
         */
        if (!(new Auth($post))->verify()) {
            $response->status(401);
            return $response->end("unauthorized");
        }

        /**
         * 发送短信端口
         */
        if ($post['port'] == $this->_smsMapStrategy) {

            if (empty($post['content']) || empty($post['mobile']) || empty($post['tem'])) {
                // 参数必须
                return $response->end("argument is required");
            }

            /**
             * 映射策略方法
             */
            if (!key_exists($post['tem'], $this->_smsMapStrategy)) {
                // 参数错误
                return $response->end("Invalid tem");
            }
        }

        /**
         * 发送邮件端口
         */
        if ($post['port'] == $this->_emsPort) {

            if (!isset($post['to']) || !isset($post['tem']) || empty($post['content'])) {
                // 参数必须
                return $response->end("argument is require");
            }

            /**
             * 映射策略方法
             */
            if (!key_exists($post['tem'], $this->_emsMapStrategy)) {
                // 参数错误
                return $response->end("Invalid tem");
            }

        }

        /**
         * 处理json
         */
        $content = json_decode($post['content'], true);
        if (empty($content) || !is_array($content)) {
            return $response->end("Invalid content");
        }
        $post['content'] = $content;


        /**
         * 开启异步任务
         */
        $this->_worker->task($post);

        /**
         * 同步返回（此环节不保证真的发送成功）
         */
        return $response->end("ok");
    }

    /**
     * @param $ser
     * @param $task_id
     * @param $from_id
     * @param $data
     */
    public function onTask($ser, $task_id, $from_id, $data)
    {

        try {
            /**
             * 任务开始数据提前写入数据库
             */
            $info = [];
            $info['tem'] = $data['tem'];
            $info['content'] = json_encode($data['content']);
            $info['app_id'] = $data['app_id'];
            $info['createtime'] = time();
            $info['updatetime'] = time();
            $info['status'] = 0;
            if ($data['port'] == $this->_smsPort) {
                $info['mobile'] = $data['mobile'];
            } else {
                $info['email'] = $data['to'];
            }
            $database = Db::instance();
            $database->insert('log', $info);
            $id = $database->id();
            $data['log_id'] = $id;

            /**
             * 发送邮件任务
             */
            if ($data['port'] == $this->_emsPort) {
                $push = (new Push())->setStrategy(new EmsSimple());
                $res = $push->msgSend(['to' => $data['to'], 'tem' => $data['tem'], 'content' => $data['content']]);
                if ($res !== true) {
                    $this->_updateStatus($id, '-1', $res);
                } else {
                    $ser->finish($data);
                }
            }

            /**
             * 发送短信任务
             */
            if ($data['port'] == $this->_smsPort) {
                $push = (new Push())->setStrategy(new SmsSimple($this->_smsMapStrategy[$data['tem']]));
                switch ($data['tem']) {
                    case 'sms_4':
                        $pushParams = ['name' => $data['content'][0], 'password' => $data['content'][1]];
                        break;
                    case 'sms_6':
                        $pushParams = ['password' => $data['content'][0]];
                        break;
                    case 'sms_7':
                        $pushParams = ['number' => $data['content'][0], 'password' => $data['content'][1]];
                        break;
                    default:
                        $pushParams = ['code' => $data['content'][0]];
                }
                $res = $push->msgSend(['mobile' => $data['mobile'], 'params' => $pushParams]);
                if ($res !== true) {
                    $this->_updateStatus($id, '-1', $res);
                } else {
                    $ser->finish($data);
                }
            }

        } catch (\Exception $exception) {
            Log::instance()->error($exception->getMessage());
        }

    }

    /**
     * 任务完成
     *
     * @param $ser
     * @param $task_id
     * @param $data
     */
    public function onFinish($ser, $task_id, $data)
    {
        try {
            $this->_updateStatus($data['log_id'], 1);
        } catch (\Exception $exception) {
            Log::instance()->error($exception->getMessage());
        }

    }

    /**
     * 更新发送消息状态
     *
     * @param int $id
     * @param $status
     * @param string $errorMsg
     */
    private function _updateStatus(int $id, $status, string $errorMsg = '')
    {
        $database = Db::instance();
        $database->update('log', ['status' => $status, 'updatetime' => time(), 'error_msg' => $errorMsg], ['id' => $id]);
    }


}